#ifndef __MANDELBROT_H__
#define __MANDELBROT_H__

#include <Python.h>
#include <iostream>
#include <numpy/arrayobject.h>
#include <cassert>
#include <iostream>
#include <cstdlib>
#include <string>
#include "./../Py/Video.h"
#include "./../Complejos/Complejo.h"

using namespace std;

#define MAX_ITERS 10 
#define WIDTH 6
#define HEIGHT WIDTH

class Mandelbrot{

 private:
	
	int* superficie;
	Float deltaX;
	Float deltaY;
	Complex posAnterior[2];
	Complex posActual[2];
	//funciones uso interno...
	int calcularPunto(Complex&);

	
	int p1,p2,p3,p4,p0;

 public:
	Mandelbrot();	
	Mandelbrot(int*);
	
	void genera(int, int);
	void genera(Complex);
	void genera(Complex&,Complex&);
	int colorear(int i);	

};


Mandelbrot::Mandelbrot(){
	
}

Mandelbrot::Mandelbrot(int* matriz){
	this->superficie = matriz;

	p0 = MAX_ITERS * 0.11;
	p1 = MAX_ITERS * 2/5;
	p2 = MAX_ITERS * 3/5;
	p3 = MAX_ITERS * 4/5;
	p4 = MAX_ITERS * 0.90;
}


int Mandelbrot::colorear(int it){
	int valor = 0xFF000000;
	int i = 0;
	int cant = 0;

	int v = 0;

	unsigned char vr = 0;
	unsigned char vg = 0;
	unsigned char vb = 0;

	float er = 0.0;
	float eg = 0.0;
	float eb = 0.0;
	
	if(it < p0){
		i = it;
		
		er = (0x00 - 0x00) / p0;
		vr = 0x00 +i*er;
		eg = (0x00 - 0x00) / p0;
		vg = 0x00 + i*eg;
		eb = (0xff - 0x45) / p0;
		vb = 0xff - i*eb;
		valor +=  vr<<16;
		valor += vg<<8;
		valor += vb;


	} else if ( it < p1){
		cant = p1 - p0;
		i = it - p0;
		er = (0x02 - 0x00) / cant;
		vr = (0x00 + i*er);
		eg = (0x99 - 0x00) / cant;
		vg = (0x00 + i*eg);
		eb = (0x55 - 0x33) / cant;
		vb = 0x55 - i*eb;
		valor +=  vr<<16;
		valor += vg<<8;
		valor += vb;
	
	} else if (it < p2){
		cant = p2 - p1;
		i = it - p1;
		er = (0xff - 0x02) / cant;
		vr = (0x02 + i*er);
		eg = (0xdd - 0x99) / cant;
		vg = (0x99 + i*eg);
		eb = (0x33 - 0x00) / cant;
		vb = 0x33 - i*eb;
		valor += vr<<16;
		valor += vg<<8;
		valor += vb;


	} else if (it < p3){
		cant = p3 - p2;
		i = it - p2;

		er = (0xff - 0xff) / cant;
		vr = (0xff + i*er);
		eg = (0xdd - 0x22) / cant;
		vg = (0xdd - i*eg);
		eb = (0x22 - 0x00) / cant;
		vb = 0x00 + i*eb;
		valor += vr<<16;
		valor += vg<<8;
		valor += vb;
	

	} else if (it < p4){
		cant = p4 - p3;
		i = it - p3;
		
		er = (0xff - 0x88) / cant;
		vr = (0xff - i*er);
		eg = (0x22 - 0x00) / cant;
		vg = (0x22 - i*eg);
		eb = (0x88 - 0x22) / cant;
		vb = 0x00 + i*eb;
		valor += vr<<16;
		valor += vg<<8;
		valor += vb;

	} else if (it < MAX_ITERS){

		cant = MAX_ITERS - p4;
		i = it - p4;

		
		er = (0x88 - 0x00) / cant;
		vr = (0x88 - i*er);
		eg = (0x00 - 0x00) / cant;
		vg = (0x00 - i*eg);
		eb = (0x88 - 0x00) / cant;
		vb = 0x88 - i*eb;
		valor += vr<<16;
		valor += vg<<8;
		valor += vb;
	} else 
		valor = 0xff000000;
	return valor;


}


int Mandelbrot::calcularPunto(Complex& x){
	inFloat aux0("0,0");
	Complex a(aux0,aux0);
	unsigned int it = 0;
	inFloat cota("4.0");
	bool seEscapo;


    	seEscapo = a.moduloModulo() > cota;

	while(it < MAX_ITERS && !seEscapo) {
		a.cuadrado();
   		a.suma(x);
   		it++;
   		seEscapo = a.moduloModulo() > cota;

    	}

	return it;
		
}


void Mandelbrot::genera(int x,int y){
	deltaX>>=1;
	deltaY>>=1;


	Float auxX((float)x);
	Float pmx = posAnterior[0].Re() + auxX * (posAnterior[1].Re() - posAnterior[0].Re())>>WIDTH;
	
	Float auxY((float)y);	
	Float pmy = posAnterior[0].Im() + auxY * (posAnterior[1].Im() - posAnterior[0].Im())>>HEIGHT;
	

	
	auxX = Float((float) WIDTH-1);
	auxY = Float((float) HEIGHT-1);
	Complex z(pmx - auxX * deltaX, pmy - auxY * deltaY);
	Complex w(pmx + auxX * deltaX, pmy + auxY * deltaY);
	

	this->genera(z,w);	
}

void Mandelbrot::genera(Complex z){}

void Mandelbrot::genera(Complex& z, Complex& w){ 
	//me guardo la posactual para la próxima
	Float Ancho = w.Re() - z.Re();
	posAnterior[0] = z;
	posAnterior[1] = w;
	
	deltaX = ( w.Re() - z.Re() )>>(WIDTH);
	deltaY = ( w.Im() - z.Im() )>>(HEIGHT);
	cout <<"z: "<< z << endl;
	cout <<"w: "<< w << endl;
	cout <<"deltaX = "<< deltaX << "/ deltaY = " << deltaY << endl;
	cout << "ancho = "<<Ancho << endl;
	int r=0;
	int c=0;
	while( z.Im() < (w.Im())  ) {
		while( z.Re() < w.Re() ) {
			cout << "C: " << c << endl;
			int i = calcularPunto(z);
			int valor =  colorear(i);
			superficie[c+r] = valor;
			c++;
			z.setRe( z.Re() + deltaX );
		}
		cout << "R: " << r << endl;
		r+= (1<<WIDTH);
		c=0;
		z.setRe(z.Re() - Ancho);
		z.setIm( z.Im() + deltaY);
	}
}

#endif

